#pragma once

#include <chrono>
#include <iostream>
#include <iterator>
#include <log.h>
#include <memory>
#include <optional>
#include <string>
#include <sw/redis++/errors.h>
#include <sw/redis++/redis.h>
#include <unordered_set>
#include <vector>


namespace lyt {
    class UserRedis{
    private:
        std::shared_ptr<sw::redis::Redis> _client;
    public:
        using ptr = std::shared_ptr<UserRedis>;
        UserRedis(const std::shared_ptr<sw::redis::Redis> &client) : _client(client) {}
        // ==============================Code的缓存======================================
        bool SetRedisCode(const std::string &key, const std::string &value, const int expire_seconds) {
            try {
                _client->set(key, value, std::chrono::seconds(expire_seconds));
                return true;
            } catch (const sw::redis::Error &err) {
                std::cerr << "SetRedisCode error: " << err.what() << std::endl;
                return false;
            }
        }
        std::optional<std::string> GetCode(const std::string &key) {
            try {
                auto val = _client->get(key);
                debuglog << "In GetCode";
                if (val)
                    return val;
            } catch (const sw::redis::Error &err) {
                std::cerr << "GetCode error: " << err.what() << std::endl;
            }
            return std::nullopt;
        }
        void DeleteCode(const std::string &key) {
            try {
                _client->del(key);
            } catch (const sw::redis::Error &err) {
                std::cerr << "DeleteCode error: " << err.what() << std::endl;
            }
        }
        // ==============================Token的缓存======================================
        // 设置token
        bool SetToken(const std::string &token, const std::string &em, int ttlSenconds) {
            try {
                _client->set(token, em, std::chrono::seconds(ttlSenconds));
                return true;
            } catch (const sw::redis::Error &err) {
                errorlog << "set token error" << err.what();
                return false;
            }
        }
        // 获取token对应的用户id
        std::optional<std::string> GetUserId(const std::string &token) {
            try {
                auto val = _client->get(token);
                if (val)
                    return val;
            } catch (const sw::redis::Error &err) {
                errorlog << "GetUserId error!" << err.what();
            }
            return std::nullopt;
        }
        // 删除token
        bool DelToken(const std::string &token) {
            try {
                // 成功删除时返回的是删除token的数量，没有token时返回的是0
                _client->del(token);
                return true;
            } catch (const sw::redis::Error &err) {
                errorlog << "DelToken failes!" << err.what();
                return false;
            }
        }
        // 刷新token的时间
        bool RefreshToken(const std::string &token, const int ttlSenconds) {
            try {
                return _client->expire(token, std::chrono::seconds(ttlSenconds));
            } catch (const sw::redis::Error &err) {
                errorlog << "failed to refresh token time!" << err.what();
                return false;
            }
        }
        // 检查token是否存在
        bool exists(const std::string &token) {
            try {
                return _client->exists(token) > 0;
            } catch (const sw::redis::Error &err) {
                return false;
            }
        }


        // ==============================UserStats的缓存======================================

        // 添加解决问题，将解决的问题全部存入set中（自动去重）
        void SetSolvedProblem(const std::string &userid, int num) {
            _client->sadd("solved:"+userid, std::to_string(num));
        }
        // 设置总问题数
        void SetTotalProblems(const std::string &userid, int total) {
            _client->set("total:"+userid, std::to_string(total));
        }
        // 只需要返回solveproblem数量即可
        int GetSovledCount(const std::string &userid) {
            return _client->scard("solved:"+userid);
        }
        // 获取题目数量
        int GetTotalProblems(const std::string &userid) {
            auto nums = _client->get("total:"+userid);
            if (nums)
                return std::stoi(*_client->get(userid));
            else
                return 0;
        }
        // 获取解决过的所有问题
        std::vector<int> GetResolvedProblems(const std::string &userid) {
            std::unordered_set<std::string> idxs;
            // smembers表示获取set的所有元素，返回的是一个列表
            // inseter是c++11中stl标准工具，返回一个插入迭代器，让第三方库把入局插入到你的容器中
            _client->smembers("solved:"+userid, std::inserter(idxs, idxs.begin()));
            std::vector<int> ret;
            for (auto idx : idxs) {
                ret.push_back(std::stoi(idx));
            }
            return ret;
        }

        // ========================================UserStatsSummary缓存==============================================
        // 存储用户统计数据到 Redis（哈希）
        bool SetRedisStatsSummary(const std::string &em, 
                                const int solved_problems,
                                const int attempting_problems,
                                const int published_blogs,
                                const int draft_blogs,
                                const int following,
                                const int followers,
                                const int mutual_friends,
                                const int blog_likes_number
                            ) {
            try {
                std::string key = "stats:" + em; // Redis Key

                std::unordered_map<std::string, std::string> fields = {{"solved_problems", std::to_string(solved_problems)},
                                                                       {"attempting_problems", std::to_string(attempting_problems)},
                                                                       {"published_blogs", std::to_string(published_blogs)},
                                                                       {"draft_blogs", std::to_string(draft_blogs)},
                                                                       {"following", std::to_string(following)},
                                                                       {"followers", std::to_string(followers)},
                                                                       {"mutual_friends", std::to_string(mutual_friends)},
                                                                       {"blog_likes_number", std::to_string(blog_likes_number)}};

                _client->hmset(key, fields.begin(), fields.end());
                // _client->expire(key, 60 * 60 * 1); // 设置1小时缓存有效期
                return true;
            } catch (const sw::redis::Error &err) {
                errorlog << "failed to set UserStatsSummary";
                return false;
            }
        }

        // 从 Redis 获取用户统计数据
        bool GetRedisStatsSummary(const std::string &em, std::vector<std::string>& summary) {
            summary.clear();
            std::string key = "stats:" + em;

            std::vector<std::string> fields = {"solved_problems", "attempting_problems", "published_blogs", "draft_blogs",
                                               "following",       "followers",           "mutual_friends",  "blog_likes_number"};

            std::vector<sw::redis::OptionalString> values;
            try {
                // 从redis中获取hash表中的fields字段，并填充到value中
                _client->hmget(key, fields.begin(), fields.end(), std::back_inserter(values));
            } catch (const std::exception &e) {
                std::cerr << "Redis error: " << e.what() << std::endl;
                return false;
            }

            if (values.size() != fields.size())
                return false;

            summary.push_back(*values[0]);
            summary.push_back(*values[1]);
            summary.push_back(*values[2]);
            summary.push_back(*values[3]);
            summary.push_back(*values[4]);
            summary.push_back(*values[5]);
            summary.push_back(*values[6]);
            summary.push_back(*values[7]);

            return true;
        }




        // ==============================UserFollower的缓存======================================
        // 添加关注关系
        bool AddFollow(const std::string& email,const std::string& target_email){
            try {
                // email关注target_email，要更改email的following和target_email的follower
                _client->sadd("following:"+email,target_email);
                _client->sadd("follower:"+target_email,email);
                return true;
            } catch (const sw::redis::Error& e) {
                errorlog << "Add follow error" << e.what();
                return false;
            }
        }
        // 取消关注
        bool UnFollow(const std::string& email,const std::string& target_email){
            try {
                _client->srem("following:"+email,target_email);
                _client->srem("follower:"+target_email, email);
                return true;
            } catch (const sw::redis::Error& e) {
                errorlog << "Cancel follow error" << e.what();
                return false;
            }
        }
        // 获取我关注的人
        std::vector<std::string> GetFollowings(const std::string& email){
            try {
                std::vector<std::string> ret;
                _client->smembers("following:", std::back_inserter(ret));
                return ret;
            } catch (const sw::redis::Error& e) {
                errorlog << "Get followings error" << e.what();
                return {};
            }
        }
        // 获取关注我的人
        std::vector<std::string> GetFollowers(const std::string& email){
            try {
                std::vector<std::string> ret;
                _client->smembers("follower:", std::back_inserter(ret));
                return ret;
            } catch (const sw::redis::Error& e) {
                errorlog << "Get followers error" << e.what();
                return {};
            }
        }
        // 获取A是否关注B
        bool IsFollow(const std::string& email,const std::string& target_email){
            try{
                return _client->sismember("following:"+email, target_email);
            }catch(const sw::redis::Error& e){
                errorlog << "Get A following B error" << e.what();
                return false;
            }
        }

        // ==============================用户版本的缓存======================================
        // 添加用户版本
        bool AddUserVersion(const std::string& email,const std::string& version){
            try {
                _client->set("version:"+email,version);
                return true;
            } catch (const sw::redis::Error& e) {
                errorlog << "AddUserVersion error" << e.what();
                return false;
            }
        }
        // 更新用户版本
        bool UpdateUserVersion(const std::string& email,const std::string& version){
            try {
                _client->set("version:"+email,version);
                return true;
            } catch (const sw::redis::Error& e) {
                errorlog << "Cancel follow error" << e.what();
                return false;
            }
        }
        // 获取用户版本
        std::string GetUserVersion(const std::string& email){
            try {
                auto val = _client->get("version:"+email);
                if(val) return *val;
            } catch (const sw::redis::Error& e) {
                errorlog << "Get followings error" << e.what();
            }
            return "";
        }
        // 删除用户版本
        bool DeleteUserVersion(const std::string& email){
            try {
                _client->del("version:"+email);
                return true;
            } catch (const sw::redis::Error& e) {
                errorlog << "Get followers error" << e.what();
                return false;
            }
        }
    };
    // class RedisCode {
    
    // public:
    //     using ptr = std::shared_ptr<RedisCode>;
    //     RedisCode(const std::shared_ptr<sw::redis::Redis> &client) : _client(client) {
    //     }
    //     bool SetRedisCode(const std::string &key, const std::string &value, const int expire_seconds) {
    //         try {
    //             _client->set(key, value, std::chrono::seconds(expire_seconds));
    //             return true;
    //         } catch (const sw::redis::Error &err) {
    //             std::cerr << "SetRedisCode error: " << err.what() << std::endl;
    //             return false;
    //         }
    //     }
    //     std::optional<std::string> GetCode(const std::string &key) {
    //         try {
    //             auto val = _client->get(key);
    //             debuglog << "In GetCode";
    //             if (val)
    //                 return val;
    //         } catch (const sw::redis::Error &err) {
    //             std::cerr << "GetCode error: " << err.what() << std::endl;
    //         }
    //         return std::nullopt;
    //     }
    //     void DeleteCode(const std::string &key) {
    //         try {
    //             _client->del(key);
    //         } catch (const sw::redis::Error &err) {
    //             std::cerr << "DeleteCode error: " << err.what() << std::endl;
    //         }
    //     }

    // private:
    //     std::shared_ptr<sw::redis::Redis> _client;
    // };

    // //
    // class RedisToken {
    // public:
    //     using ptr = std::shared_ptr<RedisToken>;
    //     RedisToken(const std::shared_ptr<sw::redis::Redis> &client) : _client(client) {
    //     }
    //     // 设置token
    //     bool SetToken(const std::string &token, const std::string &em, int ttlSenconds) {
    //         try {
    //             _client->set(token, em, std::chrono::seconds(ttlSenconds));
    //             return true;
    //         } catch (const sw::redis::Error &err) {
    //             errorlog << "set token error" << err.what();
    //             return false;
    //         }
    //     }
    //     // 获取token对应的用户id
    //     std::optional<std::string> GetUserId(const std::string &token) {
    //         try {
    //             auto val = _client->get(token);
    //             if (val)
    //                 return val;
    //         } catch (const sw::redis::Error &err) {
    //             errorlog << "GetUserId error!" << err.what();
    //         }
    //         return std::nullopt;
    //     }
    //     // 删除token
    //     bool DelToken(const std::string &token) {
    //         try {
    //             // 成功删除时返回的是删除token的数量，没有token时返回的是0
    //             _client->del(token);
    //             return true;
    //         } catch (const sw::redis::Error &err) {
    //             errorlog << "DelToken failes!" << err.what();
    //             return false;
    //         }
    //     }
    //     // 刷新token的时间
    //     bool RefreshToken(const std::string &token, const int ttlSenconds) {
    //         try {
    //             return _client->expire(token, std::chrono::seconds(ttlSenconds));
    //         } catch (const sw::redis::Error &err) {
    //             errorlog << "failed to refresh token time!" << err.what();
    //             return false;
    //         }
    //     }
    //     // 检查token是否存在
    //     bool exists(const std::string &token) {
    //         try {
    //             return _client->exists(token) > 0;
    //         } catch (const sw::redis::Error &err) {
    //             return false;
    //         }
    //     }

    // private:
    //     std::shared_ptr<sw::redis::Redis> _client;
    // };
    // class RedisStats {
    // public:
    //     using ptr = std::shared_ptr<RedisStats>;
    //     RedisStats(std::shared_ptr<sw::redis::Redis> client) : _client(client) {
    //     }
    //     // 添加解决问题，将解决的问题全部存入set中（自动去重）
    //     void SetSolvedProblem(const std::string &userid, int num) {
    //         _client->sadd("solved:"+userid, std::to_string(num));
    //     }
    //     // 设置总问题数
    //     void SetTotalProblems(const std::string &userid, int total) {
    //         _client->set("total:"+userid, std::to_string(total));
    //     }
    //     // 只需要返回solveproblem数量即可
    //     int GetSovledCount(const std::string &userid) {
    //         return _client->scard("solved:"+userid);
    //     }
    //     // 获取题目数量
    //     int GetTotalProblems(const std::string &userid) {
    //         auto nums = _client->get("total:"+userid);
    //         if (nums)
    //             return std::stoi(*_client->get(userid));
    //         else
    //             return 0;
    //     }
    //     // 获取解决过的所有问题
    //     std::vector<int> GetResolvedProblems(const std::string &userid) {
    //         std::unordered_set<std::string> idxs;
    //         // smembers表示获取set的所有元素，返回的是一个列表
    //         // inseter是c++11中stl标准工具，返回一个插入迭代器，让第三方库把入局插入到你的容器中
    //         _client->smembers("solved:"+userid, std::inserter(idxs, idxs.begin()));
    //         std::vector<int> ret;
    //         for (auto idx : idxs) {
    //             ret.push_back(std::stoi(idx));
    //         }
    //         return ret;
    //     }

    // private:
    //     std::shared_ptr<sw::redis::Redis> _client;
    // };

    // class RedisStatsSummary {
    // public:
    //     using ptr = std::shared_ptr<RedisStatsSummary>;
    //     RedisStatsSummary(std::shared_ptr<sw::redis::Redis> client) : _client(client) {
    //     }
    //     // 存储用户统计数据到 Redis（哈希）
    //     bool SetRedisStatsSummary(const std::string &em, 
    //                             const int solved_problems,
    //                             const int attempting_problems,
    //                             const int published_blogs,
    //                             const int draft_blogs,
    //                             const int following,
    //                             const int followers,
    //                             const int mutual_friends,
    //                             const int blog_likes_number
    //                         ) {
    //         try {
    //             std::string key = "stats:" + em; // Redis Key

    //             std::unordered_map<std::string, std::string> fields = {{"solved_problems", std::to_string(solved_problems)},
    //                                                                    {"attempting_problems", std::to_string(attempting_problems)},
    //                                                                    {"published_blogs", std::to_string(published_blogs)},
    //                                                                    {"draft_blogs", std::to_string(draft_blogs)},
    //                                                                    {"following", std::to_string(following)},
    //                                                                    {"followers", std::to_string(followers)},
    //                                                                    {"mutual_friends", std::to_string(mutual_friends)},
    //                                                                    {"blog_likes_number", std::to_string(blog_likes_number)}};

    //             _client->hmset(key, fields.begin(), fields.end());
    //             // _client->expire(key, 60 * 60 * 1); // 设置1小时缓存有效期
    //             return true;
    //         } catch (const sw::redis::Error &err) {
    //             errorlog << "failed to set UserStatsSummary";
    //             return false;
    //         }
    //     }

    //     // 从 Redis 获取用户统计数据
    //     bool GetRedisStatsSummary(const std::string &em, std::vector<std::string>& summary) {
    //         summary.clear();
    //         std::string key = "stats:" + em;

    //         std::vector<std::string> fields = {"solved_problems", "attempting_problems", "published_blogs", "draft_blogs",
    //                                            "following",       "followers",           "mutual_friends",  "blog_likes_number"};

    //         std::vector<sw::redis::OptionalString> values;
    //         try {
    //             // 从redis中获取hash表中的fields字段，并填充到value中
    //             _client->hmget(key, fields.begin(), fields.end(), std::back_inserter(values));
    //         } catch (const std::exception &e) {
    //             std::cerr << "Redis error: " << e.what() << std::endl;
    //             return false;
    //         }

    //         if (values.size() != fields.size())
    //             return false;

    //         summary.push_back(*values[0]);
    //         summary.push_back(*values[1]);
    //         summary.push_back(*values[2]);
    //         summary.push_back(*values[3]);
    //         summary.push_back(*values[4]);
    //         summary.push_back(*values[5]);
    //         summary.push_back(*values[6]);
    //         summary.push_back(*values[7]);

    //         return true;
    //     }

    // private:
    //     std::shared_ptr<sw::redis::Redis> _client;
    // };
    
    // class RedisFollowManager{
    // public:
    //     using ptr = std::shared_ptr<RedisFollowManager>;
    //     RedisFollowManager(){}
    //     RedisFollowManager(const std::shared_ptr<sw::redis::Redis>& client):_client(client){}
    //     // 添加关注关系
    //     bool AddFollow(const std::string& email,const std::string& target_email){
    //         try {
    //             // email关注target_email，要更改email的following和target_email的follower
    //             _client->sadd("following:"+email,target_email);
    //             _client->sadd("follower:"+target_email,email);
    //             return true;
    //         } catch (const sw::redis::Error& e) {
    //             errorlog << "Add follow error" << e.what();
    //             return false;
    //         }
    //     }
    //     // 取消关注
    //     bool UnFollow(const std::string& email,const std::string& target_email){
    //         try {
    //             _client->srem("following:"+email,target_email);
    //             _client->srem("follower:"+target_email, email);
    //             return true;
    //         } catch (const sw::redis::Error& e) {
    //             errorlog << "Cancel follow error" << e.what();
    //             return false;
    //         }
    //     }
    //     // 获取我关注的人
    //     std::vector<std::string> GetFollowings(const std::string& email){
    //         try {
    //             std::vector<std::string> ret;
    //             _client->smembers("following:", std::back_inserter(ret));
    //             return ret;
    //         } catch (const sw::redis::Error& e) {
    //             errorlog << "Get followings error" << e.what();
    //             return {};
    //         }
    //     }
    //     // 获取关注我的人
    //     std::vector<std::string> GetFollowers(const std::string& email){
    //         try {
    //             std::vector<std::string> ret;
    //             _client->smembers("follower:", std::back_inserter(ret));
    //             return ret;
    //         } catch (const sw::redis::Error& e) {
    //             errorlog << "Get followers error" << e.what();
    //             return {};
    //         }
    //     }
    //     // 获取A是否关注B
    //     bool IsFollow(const std::string& email,const std::string& target_email){
    //         try{
    //             return _client->sismember("following:"+email, target_email);
    //         }catch(const sw::redis::Error& e){
    //             errorlog << "Get A following B error" << e.what();
    //             return false;
    //         }
    //     }
    // private:
    //     std::shared_ptr<sw::redis::Redis> _client;
    // };
    // class RedisUserVersion{
    //     public:
    //         using ptr = std::shared_ptr<RedisUserVersion>;
    //         RedisUserVersion(){}
    //         RedisUserVersion(const std::shared_ptr<sw::redis::Redis>& client):_client(client){}
    //         // 添加用户版本
    //         bool AddUserVersion(const std::string& email,const std::string& version){
    //             try {
    //                 _client->set("version:"+email,version);
    //                 return true;
    //             } catch (const sw::redis::Error& e) {
    //                 errorlog << "AddUserVersion error" << e.what();
    //                 return false;
    //             }
    //         }
    //         // 更新用户版本
    //         bool UpdateUserVersion(const std::string& email,const std::string& version){
    //             try {
    //                 _client->set("version:"+email,version);
    //                 return true;
    //             } catch (const sw::redis::Error& e) {
    //                 errorlog << "Cancel follow error" << e.what();
    //                 return false;
    //             }
    //         }
    //         // 获取用户版本
    //         std::string GetUserVersion(const std::string& email){
    //             try {
    //                 auto val = _client->get("version:"+email);
    //                 if(val) return *val;
    //             } catch (const sw::redis::Error& e) {
    //                 errorlog << "Get followings error" << e.what();
    //             }
    //             return "";
    //         }
    //         // 删除用户版本
    //         bool DeleteUserVersion(const std::string& email){
    //             try {
    //                 _client->del("version:"+email);
    //                 return true;
    //             } catch (const sw::redis::Error& e) {
    //                 errorlog << "Get followers error" << e.what();
    //                 return false;
    //             }
    //         }
    //     private:
    //         std::shared_ptr<sw::redis::Redis> _client;
    // };
} // namespace lyt